/*
 * mymalloc.c
 *
 *  Created on: Feb 13, 2025
 *      Author: 35702
 */
#include "main.h"
#include "mymalloc.h"
#include "stdint.h"
/* 内存池(32字节对齐) */
// 将 mem1base 保持 32 字节对齐
__attribute__((aligned(32))) uint8_t  mem1base[MEM1_MAX_SIZE];

// 将 mem2base 保持 32 字节对齐，并放入自定义节 .mem2base
__attribute__((aligned(32))) __attribute__((section(".mem2base"))) uint8_t  mem2base[MEM2_MAX_SIZE];

// 同样将 mem2mapbase 放入自定义节 .mem2mapbase
__attribute__((section(".mem2mapbase"))) uint16_t  mem2mapbase[MEM2_ALLOC_TABLE_SIZE];
/* 内存管理表 */
uint16_t  mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                               /* 内部SRAM内存池MAP */
uint16_t  mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM2_MAX_SIZE))); /* 内部CCM内存池MAP */
/* 内存管理参数 */
const uint32_t  memtblsize[SRAMBANK]= {MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};        /* 内存表大小 */
const uint32_t  memblksize[SRAMBANK]= {MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE};                    /* 内存分块大小 */
const uint32_t  memsize[SRAMBANK]= {MEM1_MAX_SIZE,MEM2_MAX_SIZE};                           /* 内存总大小 */

/* 内存管理控制器 */
struct _m_mallco_dev mallco_dev=
{
    my_mem_init,                /* 内存初始化 */
    my_mem_perused,             /* 内存使用率 */
    mem1base,mem2base,          /* 内存池 */
    mem1mapbase,mem2mapbase,    /* 内存管理状态表 */
    0,0,                        /* 内存管理未就绪 */
};

/**
 * @brief       复制内存
 * @param       *des : 目的地址
 * @param       *src : 源地址
 * @param       n    : 需要复制的内存长度(字节为单位)
 * @retval      无
 */
void mymemcpy(void *des,void *src,uint32_t  n)
{
    uint8_t  *xdes=des;
    uint8_t  *xsrc=src;
    while(n--)*xdes++=*xsrc++;
}

/**
 * @brief       设置内存值
 * @param       *s    : 内存首地址
 * @param       c     : 要设置的值
 * @param       count : 需要设置的内存大小(字节为单位)
 * @retval      无
 */
void mymemset(void *s,uint8_t  c,uint32_t  count)
{
    uint8_t  *xs = s;
    while(count--)*xs++=c;
}

/**
 * @brief       内存管理初始化
 * @param       memx : 所属内存块
 * @retval      无
 */
void my_mem_init(uint8_t  memx)
{
    mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);    /* 内存状态表数据清零 */
    mymemset(mallco_dev.membase[memx], 0,memsize[memx]);        /* 内存池所有数据清零 */
    mallco_dev.memrdy[memx]=1;                                  /* 内存管理初始化OK */
}

/**
 * @brief       获取内存使用率
 * @param       memx : 所属内存块
 * @retval      使用率(扩大了10倍,0~1000,代表0.0%~100.0%)
 */
uint8_t  my_mem_perused(uint8_t  memx)
{
    uint32_t  used=0;
    uint32_t  i;
    for(i=0; i<memtblsize[memx]; i++)
    {
        if(mallco_dev.memmap[memx][i])used++;
    }
    return (used*100)/(memtblsize[memx]);
}

/**
 * @brief       内存分配(内部调用)
 * @param       memx : 所属内存块
 * @param       size : 要分配的内存大小(字节)
 * @retval      内存偏移地址
 *   @arg       0 ~ 0XFFFFFFFE : 有效的内存偏移地址
 *   @arg       0XFFFFFFFF     : 无效的内存偏移地址
 */
uint32_t  my_mem_malloc(uint8_t  memx,uint32_t  size)
{
    signed long offset=0;
    uint32_t  nmemb;    /* 需要的内存块数 */
    uint32_t  cmemb=0;/* 连续空内存块数 */
    uint32_t  i;
    if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);/* 未初始化,先执行初始化 */
    if(size==0)return 0XFFFFFFFF;       /* 不需要分配 */
    nmemb=size/memblksize[memx];        /* 获取需要分配的连续内存块数 */
    if(size%memblksize[memx])nmemb++;
    for(offset=memtblsize[memx]-1; offset>=0; offset--)     /* 搜索整个内存控制区 */
    {
        if(!mallco_dev.memmap[memx][offset])cmemb++;        /* 连续空内存块数增加 */
        else cmemb=0;                                       /* 连续内存块清零 */
        if(cmemb==nmemb)                                    /* 找到了连续nmemb个空内存块 */
        {
            for(i=0; i<nmemb; i++)                          /* 标注内存块非空 */
            {
                mallco_dev.memmap[memx][offset+i]=nmemb;
            }
            return (offset*memblksize[memx]);/* 返回偏移地址 */
        }
    }
    return 0XFFFFFFFF;/* 未找到符合分配条件的内存块 */
}

/**
 * @brief       释放内存(内部调用)
 * @param       memx   : 所属内存块
 * @param       offset : 内存地址偏移
 * @retval      释放结果
 *   @arg       0, 释放成功;
 *   @arg       1, 释放失败;
 *   @arg       2, 超区域了(失败);
 */
uint8_t  my_mem_free(uint8_t  memx,uint32_t  offset)
{
    int i;
    if(!mallco_dev.memrdy[memx])/* 未初始化,先执行初始化 */
    {
        mallco_dev.init(memx);
        return 1;/* 未初始化 */
    }
    if(offset<memsize[memx])/* 偏移在内存池内 */
    {
        int index=offset/memblksize[memx];          /* 偏移所在内存块号码 */
        int nmemb=mallco_dev.memmap[memx][index];   /* 内存块数量 */
        for(i=0; i<nmemb; i++)                      /* 内存块清零 */
        {
            mallco_dev.memmap[memx][index+i]=0;
        }
        return 0;
    }
    else
    {
        return 2;/* 偏移超区了 */
    }
}

/**
 * @brief       释放内存(外部调用)
 * @param       memx : 所属内存块
 * @param       ptr  : 内存首地址
 * @retval      无
 */
void myfree(uint8_t  memx,void *ptr)
{
    uint32_t  offset;
    if(ptr==NULL)return;/* 地址为0 */
    offset=(uint32_t )ptr-(uint32_t )mallco_dev.membase[memx];
    my_mem_free(memx,offset);    /* 释放内存 */
}

/**
 * @brief       分配内存(外部调用)
 * @param       memx : 所属内存块
 * @param       size : 要分配的内存大小(字节)
 * @retval      分配到的内存首地址.
 */
void *mymalloc(uint8_t  memx,uint32_t  size)
{
    uint32_t  offset;
    offset=my_mem_malloc(memx,size);
    if(offset==0XFFFFFFFF)
    {
        return NULL;
    }
    else
    {
        return (void*)((uint32_t )mallco_dev.membase[memx]+offset);
    }
}

/**
 * @brief       重新分配内存(外部调用)
 * @param       memx : 所属内存块
 * @param       *ptr : 旧内存首地址
 * @param       size : 要分配的内存大小(字节)
 * @retval      新分配到的内存首地址.
 */
void *myrealloc(uint8_t  memx,void *ptr,uint32_t  size)
{
    uint32_t  offset;
    offset=my_mem_malloc(memx,size);
    if(offset==0XFFFFFFFF)
    {
        return NULL;
    }
    else
    {
        mymemcpy((void*)((uint32_t )mallco_dev.membase[memx]+offset),ptr,size); /* 拷贝旧内存内容到新内存 */
        myfree(memx,ptr);                                                       /* 释放旧内存 */
        return (void*)((uint32_t )mallco_dev.membase[memx]+offset);             /* 返回新内存首地址 */
    }
}



////1. FLASH解锁
//HAL_StatusTypeDef HAL_FLASH_Unlock(void);
////2.FLASH上锁
//HAL_StatusTypeDef HAL_FLASH_Lock (void);
////3FLASH写入
//HAL_StatusTypeDef HAL_FLASHEx_Program(uint32_t TypeProgram, uint32_t Address ,    uint64_t Data);,
////4FLASH擦除
//HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError);
////5等待FALSH操作完成（读SR）
//HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);
//
//
////FLASH容量
//#define STM32_FLASH_SIZE 	512//单位为K
////FLASH起始地址
//#define STM32_FLASH_BASE 0x08000000
////页大小
//#define STM_SECTOR_SIZE	2048
//
//
//uint16_t STMFLASH_BUF[STM_SECTOR_SIZE/2];//FLASH读写操作页缓存空间，2K
//
////FLASH读一个半字数据 字是32位，半字是16位
//uint16_t STMFLASH_ReadHalfWord(uint32_t faddr)
//{
//    return *(uint16_t*)faddr;//利用指针直接读取返回
//}
////FLASH读(多个半字数据)，
//void STMFLASH_Read(uint32_t ReadAddr,uint16_t *PDataBuf,uint16_t Num)//参数，读取起始地址，数据指针，读取半字数
//{
//    uint16_t i;
//    for(i=0;i<Num;i++)
//    {
//        PDataBuf[i] = STMFLASH_ReadHalfWord(ReadAddr);
//        ReadAddr+=2;
//
//    }
//}
//
////FLASH写，不检查写入
//void STMFLASH_Write_NoCheck(uint32_t WriteAddr,uint16_t *PDataBuf,uint16_t Num)
//{
//    uint16_t i;
//    for(i=0;i<Num;i++)
//    {
//        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,WriteAddr,PDataBuf[i]);
//        WriteAddr+=2;
//    }
//}
//
//
////FLASH写
//void STMFLASH_Write(uint32_t WriteAddr,uint16_t *PDataBuf,uint16_t Num)
//{
//    uint32_t offset;//实际偏移地址
//    uint8_t sectornum;//扇区编号
//    uint16_t secoff;//扇区内偏移地址(16位字计算)
//    uint16_t secremain;//扇区剩余空间(16位字计算)
//    uint16_t i;
//    //地址校验
//    if((WriteAddr<STM32_FLASH_BASE)||(WriteAddr>=(STM32_FLASH_BASE+STM32_FLASH_SIZE*1024))) return ;//非法地址
//    //解锁
//    HAL_FLASH_Unlock();
//    offset=WriteAddr-STM32_FLASH_BASE;
//    sectornum=WriteAddr/STM_SECTOR_SIZE;
//    secoff=(WriteAddr%STM_SECTOR_SIZE)/2;//(2个字节为基本单位)
//    secremain=STM_SECTOR_SIZE/2-secoff;//(2个字节为基本单位)
//    if(Num<=secremain)secremain=Num;//不大于该扇区范围
//    while(1)
//    {
//        //读取该扇区内容，检验数据看是否需要擦除
//        STMFLASH_Read(STM32_FLASH_BASE+sectornum*STM_SECTOR_SIZE,STMFLASH_BUF,STM_SECTOR_SIZE/2);
//        for(i=0;i<secremain;i++)
//        {
//            if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;
//
//        }
//        if(i<secremain)//需要擦除
//        {
//            FLASH_PageErase(STM32_FLASH_BASE+sectornum*STM_SECTOR_SIZE);
//            FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
//            for(i=0;i<secremain;i++)
//            {
//                STMFLASH_BUF[secoff+i]=PDataBuf[i];
//            }
//            STMFLASH_Write_NoCheck(STM32_FLASH_BASE+sectornum*STM_SECTOR_SIZE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区
//        }
//        else
//        {
//
//            FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
//            STMFLASH_Write_NoCheck(WriteAddr,PDataBuf,secremain);//写入扇区剩余区间
//        }
//        if(secremain==Num) break;//写入结束
//        else//写入未结束
//        {
//            sectornum++;
//            secoff=0;
//            WriteAddr+=secremain*2;
//            PDataBuf+=secremain;
//            Num-=secremain;
//            if(Num>STM_SECTOR_SIZE/2)
//                secremain=STM_SECTOR_SIZE/2;
//            else
//                secremain=Num;
//        }
//    };
//    //上锁
//    HAL_FLASH_Lock();
//}
//
//
//void SystemClock_Config(void);
//const uint8_t TEXT_Buffer[]={"STM32F103 FLASH TEST"};
//#define SIZE sizeof(TEXT_Buffer)		//数组长度
//#define FLASH_SAVE_ADDR  0X08070000		//设置FLASH 保存地址(必须为偶数，且其值要大于本代码所占用FLASH的大小+0X08000000)
//int main(void)
//{
//    uint8_t i ;
//    uint8_t datatemp[SIZE];
//    HAL_Init();
//    SystemClock_Config();
//    Delay_init();
//    Led_Init();
//    UART_Init();
//    Lcd_Init();
//    LOG_INFO(Terminal0,"Chipid:%x", lcd_paramter.id);
//    STMFLASH_Write(FLASH_SAVE_ADDR,(uint16_t*)TEXT_Buffer,SIZE);
//    STMFLASH_Read(FLASH_SAVE_ADDR,(uint16_t*)datatemp,SIZE);
//    LCD_ShowString(30,190,datatemp,16);//显示读到的字符串
//    while (1)
//    {
//
//        HAL_GPIO_TogglePin(Led_DS1_GPIO_Port,Led_DS1_Pin);
//        delay_ms(500);
//
//
//    }
//}